--
-- ---------- 插件说明 ----------
-- 执行流程:
--  1. 读取缺省配置信息
--  2. 访问认证中心的获取角色信息接口
--  3. 角色鉴权
--
-- 统一错误信息处理:
-- 默认情况返回 {"code":-1, "message":"xxxxx服务错误"}
-- -----------------------------

-- 引入模块
local core = require("apisix.core")
local http = require("resty.http")
local ngx = ngx

-- 声明插件名称
local plugin_name = "tb-api-auth"

-- 定义插件 schema 格式
local schema = {
    type = "object",
    properties = {
        roles = {
            type = "array",
            minimum = 0,
            items = { type = "string" },
        },
        api_auth_path = { type = "string" },
        api_server = { type = "string" },
        rejected_code = {
            type = "integer", minimum = 200, maximum = 599, default = 403
        },
        rejected_msg = {
            type = "string", default = "无访问权限"
        },
    },
    required = { "api_auth_path", "api_server" },
}

-- 插件基础声明
local _M = {
    version = 0.1,
    priority = 6,
    name = plugin_name,
    schema = schema
}

-- 检查插件配置是否正确
function _M.check_schema(conf, schema_type)
    return core.schema.check(schema, conf)
end

local function exit(code, body)
    --if type(body) == "table" then
    --    body.code = body.code or -1
    --end
    core.response.set_header("Content-Type", "application/json")
    core.response.exit(code, body)
end

local function getApiID(conf, ctx)
    local httpc = http.new()
    httpc:set_timeout(5000)

    local serviceId = ctx.service_id or ''
    local url = conf.api_server .. '/apimgt/api/sdk/findAppId?id=' .. ctx.route_id .. '&serviceId=' .. serviceId;

    core.log.info('获取appid ', url)
    local res, err = httpc:request_uri(url, {
        keepalive = conf.keepalive,
        ssl_verify = conf.ssl_verify,
        method = "GET"
    })

    if not res then
        return nil, "访问api服务失败," .. err
    end

    if res.status ~= 200 then
        core.log.info('res.body ', res.body)
        return nil, "访问api服务失败"
    end

    local resBody = core.json.decode(res.body)

    local appId = nil
    if resBody and resBody.data and type(resBody.data) == "string" and #resBody.data > 0 then
        appId = resBody.data
    end
    core.log.info('appId ', appId)
    if not appId then
        core.log.info('res.body ', res.body)
        return nil, '路由接口未配置所属应用'
    end

    return appId, nil


end

local function find_x_cookie(value)
    if type(value) == "table" then
        for k, v in pairs(value) do
            if k == "x-cookie" then
                return tostring(v)
            end

            local result = find_x_cookie(v)
            if result then
                return result
            end
        end
    end
    return nil
end

function _M.access(conf, ctx)
    -- 接口认证地址
    local api_auth_path = conf.api_auth_path
    if api_auth_path == nil then
        exit(500, { message = "访问权限接口失败,未配置鉴权接口地址" })
    end

    local appId, err = getApiID(conf, ctx)
    if not appId then
        exit(500, { message = err })
    end

    local scheme = ctx.var.scheme
    local host = ctx.var.host
    local uri = ctx.var.request_uri
    local full_url = scheme .. "://" .. host .. uri

    local headers = core.request.headers()

    -- 获取 x-cookie 的值
    local x_cookie = headers["x-cookie"]

    if not x_cookie then
        -- 尝试从 Cookie 字段中截取 x-cookie 的值
        local cookie_header = headers["cookie"]
        if cookie_header then
            local match = cookie_header:match("x%-cookie=([^;]+)")
            if match then
                x_cookie = match
            end
        end
    end

    if not x_cookie then
        local body = core.request.get_body()

        if body then
            local body_params = core.json.decode(body)
            if body_params then
                -- 使用递归函数查找 "x-cookie"
                x_cookie = find_x_cookie(body_params)
            end
        end
    end

    -- 如果仍然没有获取到 x-cookie，则拒绝请求
    if not x_cookie then
        exit(conf.rejected_code, { message = conf.rejected_msg })
    end

    local req = {
        appId = appId,
        token = x_cookie,
        requestUrl = full_url
    }

    local reqStr = core.json.encode(req);

    headers["content-length"] = string.len(reqStr)
    headers["Content-Type"] = "application/json"

    core.log.info('请求参数', reqStr);

    local httpc = http.new()
    httpc:set_timeout(2000)
    local res, err = httpc:request_uri(api_auth_path, {
        headers = headers,
        keepalive = conf.keepalive,
        ssl_verify = conf.ssl_verify,
        method = "POST",
        body = reqStr
    })
    if not res then
        core.log.error("访问鉴权接口失败 , err: ", err)
        exit(500, { message = "访问鉴权接口失败," .. err })
    end


    local resBody = core.json.decode(res.body)
    local code = resBody.responseCode
    core.log.info("code:",code,code ~= '10001',code ~= 10001)
    local allow = code == '10001' or code == 10001
    if  not allow then
        exit(conf.rejected_code, { message = conf.rejected_msg })
    end

    -- 将userId、appName、ipAddr放入ngx.ctx中
    ctx.var.userId = resBody.data.userId
    ctx.var.appName = resBody.data.appName
    ctx.var.ipAddr = resBody.data.ipAddr


end

-- 日志阶段
function _M.log(conf, ctx)

end

return _M
